package com.zxjbyte.yiyi.framework.tenant.db.handler;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.google.common.collect.Sets;
import com.zxjbyte.yiyi.framework.common.constant.Constant;
import com.zxjbyte.yiyi.framework.common.util.AuthUtil;
import com.zxjbyte.yiyi.framework.tenant.config.TenantProperties;
import com.zxjbyte.yiyi.framework.tenant.context.YiyiTenantContextHolder;
import com.zxjbyte.yiyi.framework.tenant.annotation.TenantExclude;
import lombok.RequiredArgsConstructor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;

import java.util.*;

/**
 * 基于mybatis plus的多租户功能， 实现DB层面的多租户
 * @Author zhangxingjia
 * @Date 2023/3/14 11:06
 * @Version: 1.0
 */
@RequiredArgsConstructor
public class YiyiTenantHandler implements TenantLineHandler, SmartInitializingSingleton {

    // 自定义租户配置
    private final TenantProperties properties;

    // 匹配的多租户表
    private final Set<String> tenantTableList = Sets.newConcurrentHashSet();

    @Override
    public String getTenantIdColumn() {
        return properties.getColumn();
    }

    @Override
    public Expression getTenantId() {
        return new StringValue(StrUtil.blankToDefault(AuthUtil.getTenantId(), Constant.ADMIN_TENANT_ID));
    }

    /**
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略，false:需要解析并拼接多租户条件
     */
    @Override
    public boolean ignoreTable(String tableName) {
        if (YiyiTenantContextHolder.isIgnore()) {
            return true;
        }
        return !(tenantTableList.contains(tableName) && StrUtil.isNotBlank(AuthUtil.getTenantId()));
    }

    @Override
    public void afterSingletonsInstantiated() {
        // 单例bean实例化完成后被调用
        ApplicationContext context = SpringUtil.getApplicationContext();
        if (properties.getAnnotationExclude() && context != null) {
            Map<String, Object> tables = context.getBeansWithAnnotation(TenantExclude.class);
            Set<String> excludeTables = properties.getExcludeTables();
            for (Object o : tables.values()) {
                TenantExclude annotation = o.getClass().getAnnotation(TenantExclude.class);
                String value = annotation.value();
                excludeTables.add(value);
            }
        }
        List<TableInfo> tableInfos = TableInfoHelper.getTableInfos();
        wangCai: for (TableInfo tableInfo : tableInfos) {
            String tableName = tableInfo.getTableName();
            if (properties.getExcludeTables().contains(tableName.toLowerCase())
                    || properties.getExcludeTables().contains(tableName.toUpperCase())) {
                continue;
            }
            List<TableFieldInfo> fieldList = tableInfo.getFieldList();
            for (TableFieldInfo fieldInfo : fieldList) {
                String column = fieldInfo.getColumn();
                if (properties.getColumn().equals(column)) {
                    tenantTableList.add(tableName);
                    continue wangCai;
                }
            }
        }

    }
}
